#pragma once
#include "DGeometry.h"
#include "../DBody.h"
#include "../DSpace.h"
#include "../DVector3.h"
#include "../DVector4.h"
#include "../DMatrix3.h"
#include "../DMatrix4.h"
#include "../DQuaternion.h"
#include "../DAabb.h"
#include "../DContactInfo.h"
#include "../DContactGeom.h"
#include "../DOde.h"

namespace Skill
{
	namespace Ode
	{
		namespace Geometries
		{
			void DGeometry::CollectManagedMemory()
			{				
				_WorldMatrix = nullptr;
				_Rotation = nullptr;
				_Position = nullptr;
				_Quaternion = nullptr;								
				_OffsetPosition = nullptr;
				_OffsetRotation = nullptr;
				_OffsetQuaternion = nullptr;
				DSpace::CollectManagedMemory();
			}
			DGeometry::!DGeometry()
			{
				if(_Free && _This && DOde::IsInitialized)
					dGeomDestroy(_Geom());
				_This = nullptr;
				_Free = false;
				_Disposed = true;					
			}						

			DBody^ DGeometry::Body::get()
			{
				if(IsSpace) return nullptr;
				return _Body;
			}
			void DGeometry::Body::set(DBody^ value)
			{
				if(IsSpace) return;
				_Body = value;
				if(_Body)
					dGeomSetBody(_Geom(), _Body->_This);
				else
					dGeomSetBody(_Geom(),NULL);
			}

			DVector3^ DGeometry::Position::get()
			{
				if(IsSpace) return nullptr;
				if(!_Position)
					_Position = gcnew DVector3();
				dGeomCopyPosition(_Geom(),_Position->_This);
				return _Position;
			}
			void DGeometry::Position::set(DVector3^ value)
			{				
				if(IsSpace) return;
				dGeomSetPosition(_Geom(),value->_This[0],value->_This[1],value->_This[2]);
			}

			DMatrix3^ DGeometry::Rotation::get()
			{
				if(IsSpace) return nullptr;
				if(!_Rotation)
					_Rotation = gcnew DMatrix3();
				dGeomCopyRotation(_Geom(),_Rotation->_This);
				return _Rotation;
			}
			void DGeometry::Rotation::set(DMatrix3^ value)
			{				
				if(IsSpace) return;
				dGeomSetRotation(_Geom(),value->_This);
			}

			DMatrix3^ DGeometry::WorldMatrix::get()
			{
				if(IsSpace) return nullptr;
				if(!_WorldMatrix)
					_WorldMatrix = gcnew DMatrix3();
				dGeomCopyRotation(_Geom(),_WorldMatrix->_This);
				const dReal* p = dGeomGetPosition(_Geom());
				_WorldMatrix->_This[3]  = p[0];
				_WorldMatrix->_This[7]  = p[1];
				_WorldMatrix->_This[11] = p[2];
				return _WorldMatrix;
			}
			void DGeometry::WorldMatrix::set(DMatrix3^ value)
			{				
				if(IsSpace) return;
				dGeomSetRotation(_Geom(),value->_This);
				dGeomSetPosition(_Geom(),value->_This[3],value->_This[7],value->_This[11]);
			}



			DQuaternion^ DGeometry::Quaternion::get()
			{
				if(IsSpace) return nullptr;
				if(!_Quaternion)
					_Quaternion = gcnew DQuaternion();
				dGeomGetQuaternion(_Geom(),_Quaternion->_This);
				return _Quaternion;
			}
			void DGeometry::Quaternion::set(DQuaternion^ value)
			{				
				if(IsSpace) return;
				dGeomSetQuaternion(_Geom(),value->_This);
			}

			DAabb^ DGeometry::Aabb::get()
			{				
				if(!_Aabb)
					_Aabb = gcnew DAabb();
				dGeomGetAABB(_Geom(),_Aabb->_This);
				return _Aabb;				
			}						

			int DGeometry::ClassID::get()
			{
				if(IsSpace) return Int32::MinValue;
				return dGeomGetClass(_Geom());
			}

			unsigned long DGeometry::CategoryBits::get()
			{
				if(IsSpace) return 0;
				return dGeomGetCategoryBits(_Geom());
			}
			void DGeometry::CategoryBits::set(unsigned long value)
			{
				if(IsSpace) return;
				dGeomSetCategoryBits(_Geom(),value);
			}

			unsigned long DGeometry::CollideBits::get()
			{
				if(IsSpace) return 0;
				return dGeomGetCollideBits(_Geom());
			}
			void DGeometry::CollideBits::set(unsigned long value)
			{
				if(IsSpace) return;
				dGeomSetCollideBits(_Geom(),value);
			}

			void DGeometry::Enable()
			{
				if(IsSpace) return;
				dGeomEnable(_Geom());
			}
			void DGeometry::Disable()
			{
				if(IsSpace) return;
				dGeomDisable(_Geom());
			}

			bool DGeometry::IsEnabled::get()
			{
				if(IsSpace) return false;
				return dGeomIsEnabled(_Geom()) == 1;
			}

			DVector3^ DGeometry::OffsetPosition::get()
			{
				if(IsSpace) return nullptr;
				if(!_OffsetPosition)
					_OffsetPosition = gcnew DVector3();
				dGeomCopyOffsetPosition(_Geom(),_OffsetPosition->_This);
				return _OffsetPosition;
			}
			void DGeometry::OffsetPosition::set(DVector3^ value)
			{				
				if(IsSpace) return;
				dGeomSetOffsetPosition(_Geom(),value->_This[0],value->_This[1],value->_This[2]);
			}

			DMatrix3^ DGeometry::OffsetRotation::get()
			{
				if(IsSpace) return nullptr;
				if(!_OffsetRotation)
					_OffsetRotation = gcnew DMatrix3();
				dGeomCopyOffsetRotation(_Geom(),_OffsetRotation->_This);
				return _OffsetRotation;
			}
			void DGeometry::OffsetRotation::set(DMatrix3^ value)
			{				
				if(IsSpace) return;
				dGeomSetOffsetRotation(_Geom(),value->_This);
			}

			DQuaternion^ DGeometry::OffsetQuaternion::get()
			{
				if(IsSpace) return nullptr;
				if(!_OffsetQuaternion)
					_OffsetQuaternion = gcnew DQuaternion();
				dGeomGetOffsetQuaternion(_Geom(),_OffsetQuaternion->_This);
				return _OffsetQuaternion;
			}
			void DGeometry::OffsetQuaternion::set(DQuaternion^ value)
			{				
				if(IsSpace) return;
				dGeomSetOffsetQuaternion(_Geom(),value->_This);
			}			


			void DGeometry::SetOffsetWorldPosition(DVector3^ offset)
			{
				if(IsSpace) return;
				dGeomSetOffsetWorldPosition(_Geom(),offset->_This[0],offset->_This[1],offset->_This[2]);
			}
			void DGeometry::SetOffsetWorldRotation(DMatrix3^ offset)
			{
				if(IsSpace) return;
				dGeomSetOffsetWorldRotation(_Geom(),offset->_This);
			}
			void DGeometry::SetOffsetWorldQuaternion(DQuaternion^ offset)
			{
				if(IsSpace) return;
				dGeomSetOffsetWorldQuaternion(_Geom(),offset->_This);
			}

			void DGeometry::ClearOffset()
			{
				if(IsSpace) return;
				dGeomClearOffset(_Geom());
			}

			bool DGeometry::IsOffset::get()
			{
				if(IsSpace) return false;
				return dGeomIsOffset(_Geom()) == 1;
			}						
			int DGeometry::Collide(DSpace^ o1, DSpace^ o2, int flags, DContactInfoArray^ contacts)
			{				
				return dCollide((dGeomID)o1->_This,(dGeomID)o2->_This,flags,&contacts->_This[0].geom,DContactInfo::SizeInBytes);				
			}
		}
	}
}